using System;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace SBPweb.Security.Authorization
{
	/// <summary>
	/// class of SIDHandler
	/// </summary>
	public class SIDHandler
	{

		#region Private external methods

		/// <summary>
		/// Lookup account SID
		/// </summary>
		/// <param name="systemName">system name</param>
		/// <param name="sid">sid</param>
		/// <param name="name">name</param>
		/// <param name="cbName">name</param>
		/// <param name="referencedDomainName">referenced domain name</param>
		/// <param name="cbReferencedDomainName">referenced domain name</param>
		/// <param name="use">use</param>
		/// <returns>success</returns>
		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		private static extern bool LookupAccountSid(
			[In, MarshalAs(UnmanagedType.LPTStr)] string systemName,
			IntPtr sid,
			[Out, MarshalAs(UnmanagedType.LPTStr)] StringBuilder name,
			ref int cbName,
			StringBuilder referencedDomainName,
			ref int cbReferencedDomainName,
			out int use);

		/// <summary>
		/// Lookup account name
		/// </summary>
		/// <param name="systemName">system name</param>
		/// <param name="accountName">account name</param>
		/// <param name="sid">sid</param>
		/// <param name="cbSid">sid</param>
		/// <param name="referencedDomainName">referenced domain name</param>
		/// <param name="cbReferencedDomainName">referenced domain name</param>
		/// <param name="use">use</param>
		/// <returns>success</returns>
		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern bool LookupAccountName(
			[In, MarshalAs(UnmanagedType.LPTStr)] string systemName,
			[In, MarshalAs(UnmanagedType.LPTStr)] string accountName,
			IntPtr sid,
			ref int cbSid,
			StringBuilder referencedDomainName,
			ref int cbReferencedDomainName,
			out int use);

		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		internal static extern bool ConvertSidToStringSid(
			IntPtr sid,
			[In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);

		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		internal static extern bool ConvertStringSidToSid(
			[In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid,
			ref IntPtr sid);

		/// <summary>
		/// Logon user
		/// </summary>
		/// <param name="lpszUsername">username</param>
		/// <param name="lpszDomain">domain</param>
		/// <param name="lpszPassword">password</param>
		/// <param name="dwLogonType">logon type</param>
		/// <param name="dwLogonProvider">logon provider</param>
		/// <param name="phToken">token</param>
		/// <returns>user</returns>
		[DllImport("advapi32.dll", SetLastError = true)]
		public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
			int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

		/// <summary>
		/// Close handle
		/// </summary>
		/// <param name="handle">handle</param>
		/// <returns>success</returns>
		[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
		public extern static bool CloseHandle(IntPtr handle);

		/// <summary>
		/// Duplicate token
		/// </summary>
		/// <param name="ExistingTokenHandle">existing token handle</param>
		/// <param name="SECURITY_IMPERSONATION_LEVEL">security impresonation level</param>
		/// <param name="DuplicateTokenHandle">duplicate token handle</param>
		/// <returns>true or false</returns>
		[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
			int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

		#endregion

		#region Public methods

		/// <summary>
		/// Get SID
		/// </summary>
		/// <param name="name">name of sid</param>
		/// <returns>string</returns>
		public static string GetSid(string name)
		{
			IntPtr _sid = IntPtr.Zero;    //pointer to binary form of SID string.
			int _sidLength = 0;            //size of SID buffer.
			int _domainLength = 0;        //size of domain name buffer.
			int _use;                    //type of object.
			//stringBuilder for domain name.
			StringBuilder _domain = new StringBuilder();
			int _error = 0;
			string _sidString = "";

			//first call of the function only returns the size 
			//of buffers (SID, domain name)
			LookupAccountName(null, name, _sid, ref _sidLength, _domain,
							   ref _domainLength, out _use);
			_error = Marshal.GetLastWin32Error();

			//error 122 (The data area passed to a system call is too small) 
			// normal behaviour.
			if (_error != 122)
			{
				throw (new System.Exception(new Win32Exception(_error).Message));
			}
			else
			{
				//allocates memory for domain name
				_domain = new StringBuilder(_domainLength);
				//allocates memory for SID
				_sid = Marshal.AllocHGlobal(_sidLength);
				bool _rc = LookupAccountName(null, name, _sid, ref _sidLength, _domain,
										  ref _domainLength, out _use);

				if (_rc == false)
				{
					_error = Marshal.GetLastWin32Error();
					Marshal.FreeHGlobal(_sid);
					throw (new System.Exception(new Win32Exception(_error).Message));
				}
				else
				{
					// converts binary SID into string
					_rc = ConvertSidToStringSid(_sid, ref _sidString);

					if (_rc == false)
					{
						_error = Marshal.GetLastWin32Error();
						Marshal.FreeHGlobal(_sid);
						throw (new System.Exception(new Win32Exception(_error).Message));
					}
					else
					{
						Marshal.FreeHGlobal(_sid);
						return _sidString;
					}
				}
			}

		}

		/// <summary>
		/// Get pointer of SID
		/// </summary>
		/// <param name="name">name of sid</param>
		/// <returns>pointer</returns>
		public static IntPtr GetSidPtr(string name)
		{
			IntPtr _sid = IntPtr.Zero;    //pointer to binary form of SID string.
			int _sidLength = 0;            //size of SID buffer.
			int _domainLength = 0;        //size of domain name buffer.
			int _use;                    //type of object.
			//stringBuilder for domain name.
			StringBuilder _domain = new StringBuilder();
			int _error = 0;

			//first call of the function only returns the size 
			//of buffers (SID, domain name)
			LookupAccountName(null, name, _sid, ref _sidLength, _domain,
							   ref _domainLength, out _use);
			_error = Marshal.GetLastWin32Error();

			//error 122 (The data area passed to a system call is too small) 
			// normal behaviour.
			if (_error != 122)
			{
				throw (new System.Exception(new Win32Exception(_error).Message));
			}
			else
			{
				//allocates memory for domain name
				_domain = new StringBuilder(_domainLength);
				//allocates memory for SID
				_sid = Marshal.AllocHGlobal(_sidLength);
			}

			return _sid;
		}

		/// <summary>
		/// Duplicate token
		/// </summary>
		/// <param name="iptr">pointer</param>
		/// <returns>pointer</returns>
		public static IntPtr DuplicateToken(IntPtr iptr)
		{
			IntPtr ret = IntPtr.Zero;
			bool r = DuplicateToken(iptr, 0, ref ret);
			return ret;
		}

		/// <summary>
		/// Get name of SID
		/// </summary>
		/// <param name="sid">sid</param>
		/// <returns>string</returns>
		public static string GetName(string sid)
		{
			IntPtr _sid = IntPtr.Zero;    //pointer to binary form of SID string.
			int _nameLength = 0;        //size of object name buffer
			int _domainLength = 0;        //size of domain name buffer
			int _use;                    //type of object
			StringBuilder _domain = new StringBuilder();    //domain name variable
			int _error = 0;
			StringBuilder _name = new StringBuilder();        //object name variable

			//converts SID string into the binary form
			bool _rc0 = ConvertStringSidToSid(sid, ref _sid);

			if (_rc0 == false)
			{
				_error = Marshal.GetLastWin32Error();
				Marshal.FreeHGlobal(_sid);
				throw (new System.Exception(new Win32Exception(_error).Message));
			}

			//first call of method returns the size of domain name 
			//and object name buffers
			bool _rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain,
							 ref _domainLength, out _use);
			_domain = new StringBuilder(_domainLength);    //allocates memory for domain name
			_name = new StringBuilder(_nameLength);        //allocates memory for object name
			_rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain,
							 ref _domainLength, out _use);

			if (_rc == false)
			{
				_error = Marshal.GetLastWin32Error();
				Marshal.FreeHGlobal(_sid);
				throw (new System.Exception(new Win32Exception(_error).Message));
			}
			else
			{
				Marshal.FreeHGlobal(_sid);
				return _domain.ToString() + "\\" + _name.ToString();
			}
		}

		#endregion
	
	}
}
